
/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */


#ifndef _NGX_HTTP_CORE_H_INCLUDED_
#define _NGX_HTTP_CORE_H_INCLUDED_


#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>


#define NGX_HTTP_GZIP_PROXIED_OFF       0x0002
#define NGX_HTTP_GZIP_PROXIED_EXPIRED   0x0004
#define NGX_HTTP_GZIP_PROXIED_NO_CACHE  0x0008
#define NGX_HTTP_GZIP_PROXIED_NO_STORE  0x0010
#define NGX_HTTP_GZIP_PROXIED_PRIVATE   0x0020
#define NGX_HTTP_GZIP_PROXIED_NO_LM     0x0040
#define NGX_HTTP_GZIP_PROXIED_NO_ETAG   0x0080
#define NGX_HTTP_GZIP_PROXIED_AUTH      0x0100
#define NGX_HTTP_GZIP_PROXIED_ANY       0x0200


#define NGX_HTTP_AIO_OFF                0
#define NGX_HTTP_AIO_ON                 1
#define NGX_HTTP_AIO_SENDFILE           2


#define NGX_HTTP_SATISFY_ALL            0
#define NGX_HTTP_SATISFY_ANY            1


#define NGX_HTTP_LINGERING_OFF          0
#define NGX_HTTP_LINGERING_ON           1
#define NGX_HTTP_LINGERING_ALWAYS       2


#define NGX_HTTP_IMS_OFF                0
#define NGX_HTTP_IMS_EXACT              1
#define NGX_HTTP_IMS_BEFORE             2


#define NGX_HTTP_KEEPALIVE_DISABLE_NONE    0x0002
#define NGX_HTTP_KEEPALIVE_DISABLE_MSIE6   0x0004
#define NGX_HTTP_KEEPALIVE_DISABLE_SAFARI  0x0008


typedef struct ngx_http_location_tree_node_s  ngx_http_location_tree_node_t;
typedef struct ngx_http_core_loc_conf_s  ngx_http_core_loc_conf_t;


typedef struct {
    union {
        struct sockaddr        sockaddr;
        struct sockaddr_in     sockaddr_in;
#if (NGX_HAVE_INET6)
        struct sockaddr_in6    sockaddr_in6;
#endif
#if (NGX_HAVE_UNIX_DOMAIN)
        struct sockaddr_un     sockaddr_un;
#endif
        u_char                 sockaddr_data[NGX_SOCKADDRLEN];
    } u;

    socklen_t                  socklen;

    unsigned                   set:1; //fzc:? 目前未确定, 貌似表示当出现多个server有相同addr:port时, 那最后生成的conf_addr要以lsopt->set置位的server为准.
    unsigned                   default_server:1; //fzc: 为1时表示listen指令的参数使用了default_server
    unsigned                   bind:1; //fzc: 为1时标识需要绑定本地端口, listen指令的setfib, fastopen等选项其实都隐式的表示使用bind参数, 即使这时listen指令没有使用bind参数, 也会把lsopt->bind置位
    unsigned                   wildcard:1; //fzc: 为1时表示该listening监听的addr:port使用了通配符
#if (NGX_HTTP_SSL)
    unsigned                   ssl:1;
#endif
#if (NGX_HTTP_SPDY)
    unsigned                   spdy:1;
#endif
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
    unsigned                   ipv6only:1;
#endif
    unsigned                   so_keepalive:2;
    unsigned                   proxy_protocol:1;

    int                        backlog;
    int                        rcvbuf;
    int                        sndbuf;
#if (NGX_HAVE_SETFIB)
    int                        setfib;
#endif
#if (NGX_HAVE_TCP_FASTOPEN)
    int                        fastopen;
#endif
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
    int                        tcp_keepidle;
    int                        tcp_keepintvl;
    int                        tcp_keepcnt;
#endif

#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
    char                      *accept_filter;
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
    ngx_uint_t                 deferred_accept;
#endif

    u_char                     addr[NGX_SOCKADDR_STRLEN + 1];
} ngx_http_listen_opt_t; //fzc: 主要是在ngx_http_core_listen中初始化, ngx_http_listen_opt_t中的成员主要根据listen指令的参数来初始化


typedef enum { //fzc: 共11个phase, 只能介入7个, 4个不可介入, 可介入的7个只用了4个共享的checker
    NGX_HTTP_POST_READ_PHASE = 0, //fzc: checker为ngx_http_core_generic_phase

    NGX_HTTP_SERVER_REWRITE_PHASE,

    NGX_HTTP_FIND_CONFIG_PHASE, //fzc: 不可介入
    NGX_HTTP_REWRITE_PHASE,
    NGX_HTTP_POST_REWRITE_PHASE, //fzc: 不可介入

    NGX_HTTP_PREACCESS_PHASE, //fzc: checker为ngx_http_core_generic_phase

    NGX_HTTP_ACCESS_PHASE,
    NGX_HTTP_POST_ACCESS_PHASE, //fzc: 不可介入

    NGX_HTTP_TRY_FILES_PHASE, //fzc: 只为try_files开辟的phase, 不可介入
    NGX_HTTP_CONTENT_PHASE,

    NGX_HTTP_LOG_PHASE //fzc: checker为ngx_http_core_generic_phase, ngx_http_log_module对该phase添加了handler, 该阶段不会在ngx_http_core_run_phases中像其他阶段handler那样被依次调用, 而是在ngx_http_free_request中被调用的.
} ngx_http_phases;

typedef struct ngx_http_phase_handler_s  ngx_http_phase_handler_t;

typedef ngx_int_t (*ngx_http_phase_handler_pt)(ngx_http_request_t *r,
    ngx_http_phase_handler_t *ph);

struct ngx_http_phase_handler_s { //fzc: 表示一个phase里的一个handler, 任意一个ngx_http_phases阶段, 都可以有零个或多个handler
    ngx_http_phase_handler_pt  checker; //fzc: 每个phase的不同handler对应的的checker都是一致的, 不同的是handler, checker中做一些输入输出检查, 并遍历调用该阶段的handler, http框架调用checker而不直接调用handler, 除非该阶段的checker没有实现, checker方法是不允许用户定义的, 由http框架实现
    ngx_http_handler_pt        handler; //fzc: 这里命名有点混乱, 注意checker调用handler, 也就是ngx_http_phase_handler_pt会调用ngx_http_handler_pt, 他们都由ngx_http_phase_handler_s组织, 注意除了ngx_http_core_module以外的http模块只能通过定义handler介入某个http处理阶段处理请求
    ngx_uint_t                 next; //fzc: 表示下一个处理阶段中的第一个handler下标, 用于非顺序的执行handler, 可以往前跳, 不执行某些handler, 也可以往后跳, 重复执行一些handler
};


typedef struct {
    ngx_http_phase_handler_t  *handlers; //fzc: ngx_http_phase_handler_s数组
    ngx_uint_t                 server_rewrite_index; //fzc: NGX_HTTP_SERVER_REWRITE_PHASE阶段的第一个handler下标, 用于在任意阶段快速跳回到NGX_HTTP_SERVER_REWRITE_PHASE阶段处理请求
    ngx_uint_t                 location_rewrite_index; //fzc: NGX_HTTP_REWRITE_PHASE阶段的第一个handler下标, 用于在任意阶段快速跳回到NGX_HTTP_REWRITE_PHASE阶段处理请求
} ngx_http_phase_engine_t; //fzc:!! 所有http模块合作处理模块的基石, http框架解析完http{}后生成的, 因此是存储在全局唯一的ngx_http_core_main_conf_t中的.


typedef struct {
    ngx_array_t                handlers; //fzc: 元素为ngx_http_handler_pt
} ngx_http_phase_t;


typedef struct {
    ngx_array_t                servers;         /* ngx_http_core_srv_conf_t */ //fzc: 数组元素指向ngx_http_core_svr_conf_t, 然后通过ctx成员获取到server block所在的ngx_http_conf_ctx_t, 而实际使用不会直接遍历该数组, 而是通过下面ports数组中散列表来快速找到server

    ngx_http_phase_engine_t    phase_engine; //fzc: 阶段引擎, 高大上的名字, 包含所有http模块的ngx_http_phase_handler_s数组

    ngx_hash_t                 headers_in_hash; //fzc: 在ngx_http_init_headers_in_hash中被初始化

    ngx_hash_t                 variables_hash; //fzc: 在ngx_http_variables_init_vars中建立, 仅在ngx_http_get_variable中被使用

    ngx_array_t                variables;       /* ngx_http_variable_t */
    ngx_uint_t                 ncaptures;

    ngx_uint_t                 server_names_hash_max_size;
    ngx_uint_t                 server_names_hash_bucket_size;

    ngx_uint_t                 variables_hash_max_size;
    ngx_uint_t                 variables_hash_bucket_size;

    ngx_hash_keys_arrays_t    *variables_keys; //fzc: 在ngx_http_variables_add_core_vars中初始化, 并加入core_module的变量, 之后需要添加变量则调用ngx_http_add_variable

    ngx_array_t               *ports; //fzc: 包含server块中listen指令指定的监听端口信息, 元素为ngx_http_conf_port_t, http框架通过port和可通配的地址快速找到对应的ngx_http_core_srv_conf_t结构体, 该成员是在ngx_http_core_listen->ngx_http_add_listen中建立的

    ngx_uint_t                 try_files;       /* unsigned  try_files:1 */ //fzc: 标识配置中是否使用到try_files指令

    ngx_http_phase_t           phases[NGX_HTTP_LOG_PHASE + 1]; //fzc: 实际上是一个ngx_array_t, 元素是ngx_http_handler_pt, 因此每个数组代表一个phase, 共11个动态数组, 是http框架启动过程中用到的临时变量, 任何http模块都在一个在ngx_http_module_t的postconfiguration回调中将自定义的handler回调添加到对应阶段phase->handlers动态数组中来, 而http框架最终会将这些handler添加到phase_engine中去, 对于NGX_HTTP_CONTENT_PHASE中还有另一种初始化方法.
} ngx_http_core_main_conf_t;


typedef struct {
    /* array of the ngx_http_server_name_t, "server_name" directive */
    ngx_array_t                 server_names; //fzc: 遇到server_name指令, 在ngx_http_core_server_name中添加ngx_http_server_name_t

    /* server ctx */
    ngx_http_conf_ctx_t        *ctx; //fzc: 指向配置结构体自身的server block的ngx_http_conf_ctx_t

    ngx_str_t                   server_name; //fzc: 在ngx_http_core_merge_srv_conf中取server_names数组的第一个元素

    size_t                      connection_pool_size;
    size_t                      request_pool_size;
    size_t                      client_header_buffer_size;

    ngx_bufs_t                  large_client_header_buffers;

    ngx_msec_t                  client_header_timeout;

    ngx_flag_t                  ignore_invalid_headers;
    ngx_flag_t                  merge_slashes;
    ngx_flag_t                  underscores_in_headers;

    unsigned                    listen:1; //fzc: 为1时表示该server{}中使用到了listen命令
#if (NGX_PCRE)
    unsigned                    captures:1; //fzc: 为1时标识server_name指令的参数使用了正则, 且正则里使用了后向引用
#endif

    ngx_http_core_loc_conf_t  **named_locations;
} ngx_http_core_srv_conf_t;


/* list of structures to find core_srv_conf quickly at run time */


typedef struct {
#if (NGX_PCRE)
    ngx_http_regex_t          *regex; //fzc: 使用ngx_http_regex_compile的返回值
#endif
    ngx_http_core_srv_conf_t  *server;   /* virtual name server conf */
    ngx_str_t                  name; //fzc: 在server_name指令没有使用正则时,name会转换为小写存储
} ngx_http_server_name_t; //fzc: 遇到server_name指令, 通过ngx_http_core_server_name解析, 解析出的server_name会存储在cscf->servers


typedef struct {
     ngx_hash_combined_t       names;

     ngx_uint_t                nregex;
     ngx_http_server_name_t   *regex;
} ngx_http_virtual_names_t; //fzc: 构造逻辑详见ngx_http_add_addrs


struct ngx_http_addr_conf_s {
    /* the default server configuration for this address:port */
    ngx_http_core_srv_conf_t  *default_server;

    ngx_http_virtual_names_t  *virtual_names;

#if (NGX_HTTP_SSL)
    unsigned                   ssl:1;
#endif
#if (NGX_HTTP_SPDY)
    unsigned                   spdy:1;
#endif
    unsigned                   proxy_protocol:1; //fzc:? 在ngx_http_init_connection会赋值给ngx_http_connection_t->proxy_protocol, 那自己在哪里赋值?
};


typedef struct {
    in_addr_t                  addr; //fzc: 等于ngx_http_conf_addr_t.opt.u.sockaddr_in.sin_addr.s_addr
    ngx_http_addr_conf_t       conf; //fzc: 其成员都在ngx_http_add_addrs方法中用ngx_http_conf_addr_t的成员赋值
} ngx_http_in_addr_t; //fzc: 在ngx_http_add_addrs中构造


#if (NGX_HAVE_INET6)

typedef struct {
    struct in6_addr            addr6;
    ngx_http_addr_conf_t       conf;
} ngx_http_in6_addr_t;

#endif


typedef struct {
    /* ngx_http_in_addr_t or ngx_http_in6_addr_t */
    void                      *addrs;
    ngx_uint_t                 naddrs;
} ngx_http_port_t;


typedef struct {
    ngx_int_t                  family;
    in_port_t                  port;
    ngx_array_t                addrs;     /* array of ngx_http_conf_addr_t */ //fzc: 一个机器上可能多一个ip地址
} ngx_http_conf_port_t; //fzc: 在ngx_http_add_listen中通过ngx_http_add_addresses添加ngx_http_conf_addr_t, 只有port和family相同才放到同个port里


typedef struct {
    ngx_http_listen_opt_t      opt; //fzc: 监听套接字的各种选项, 注意这里opt不是数组, 即opt是addr单位的, 多个server共享, 看ngx_http_add_addresses中是怎么处理同个addr中的多个server的opt

    ngx_hash_t                 hash; //fzc: 完美匹配的散列表, 以下三个散列表用于通过server_name来快速找到对应的server块, 是在ngx_http_optimize_servers->ngx_http_server_names中建立, key是ngx_str_t即server_name, value是ngx_http_core_srv_conf_t*
    ngx_hash_wildcard_t       *wc_head; //fzc: 通配符前置的散列表
    ngx_hash_wildcard_t       *wc_tail; //fzc: 通配符后置的散列表

#if (NGX_PCRE)
    ngx_uint_t                 nregex; //fzc: regex数组的元素个数, 即数组大小
    ngx_http_server_name_t    *regex; //fzc: 见ngx_http_server_names, 数组, 存储使用了正则的server_name指令参数
#endif

    /* the default server configuration for this address:port */
    ngx_http_core_srv_conf_t  *default_server; //fzc: 如果只有一个server, 那么default_server就指向这个server, 但如果同addr:port下不止一个server, 那这些server里只能有一个的listen指令加default_server参数, 否则报错
    ngx_array_t                servers;  /* array of ngx_http_core_srv_conf_t */ //fzc: 这里说明即使一个端口一个ip地址也可能对应多个server块, 要根据上面讲到的散列表以server_name为key来找对应的ngx_http_core_srv_conf_t, 注意这里元素为ngx_http_core_srv_conf_t**, 在ngx_http_add_server中添加元素, 注意这里的servers数组会被ngx_http_optimize_servers中被排序, 明确需要bind()ed的server靠前, 含通配符的靠后.
} ngx_http_conf_addr_t;


typedef struct {
    ngx_int_t                  status;
    ngx_int_t                  overwrite;
    ngx_http_complex_value_t   value;
    ngx_str_t                  args;
} ngx_http_err_page_t;


typedef struct {
    ngx_array_t               *lengths;
    ngx_array_t               *values;
    ngx_str_t                  name;

    unsigned                   code:10;
    unsigned                   test_dir:1;
} ngx_http_try_file_t;


struct ngx_http_core_loc_conf_s {
    ngx_str_t     name;          /* location name */ //fzc: 就是location指令后面路由名, 不包括路由匹配模式参数

#if (NGX_PCRE)
    ngx_http_regex_t  *regex; //fzc: regex成员是否有值可以作为是否该location是否使用了regex location的依据
#endif

    unsigned      noname:1;   /* "if () {}" block or limit_except */
    unsigned      lmt_excpt:1;
    unsigned      named:1;

    unsigned      exact_match:1; //fzc: 精准匹配, eg. location = $name {...}
    unsigned      noregex:1;

    unsigned      auto_redirect:1;
#if (NGX_HTTP_GZIP)
    unsigned      gzip_disable_msie6:2;
#if (NGX_HTTP_DEGRADATION)
    unsigned      gzip_disable_degradation:2;
#endif
#endif

    ngx_http_location_tree_node_t   *static_locations;
#if (NGX_PCRE)
    ngx_http_core_loc_conf_t       **regex_locations;
#endif

    /* pointer to the modules' loc_conf */
    void        **loc_conf; //fzc: 不指向ngx_http_conf_ctx_t, 而指向其中的loc_conf指针数组, 这点和ngx_http_core_svr_conf_t不同

    uint32_t      limit_except;
    void        **limit_except_loc_conf;

    ngx_http_handler_pt  handler;

    /* location name length for inclusive location with inherited alias */
    size_t        alias;
    ngx_str_t     root;                    /* root, alias */
    ngx_str_t     post_action;

    ngx_array_t  *root_lengths;
    ngx_array_t  *root_values;

    ngx_array_t  *types;
    ngx_hash_t    types_hash;
    ngx_str_t     default_type;

    off_t         client_max_body_size;    /* client_max_body_size */
    off_t         directio;                /* directio */
    off_t         directio_alignment;      /* directio_alignment */

    size_t        client_body_buffer_size; /* client_body_buffer_size */
    size_t        send_lowat;              /* send_lowat */
    size_t        postpone_output;         /* postpone_output */
    size_t        limit_rate;              /* limit_rate */
    size_t        limit_rate_after;        /* limit_rate_after */
    size_t        sendfile_max_chunk;      /* sendfile_max_chunk */
    size_t        read_ahead;              /* read_ahead */

    ngx_msec_t    client_body_timeout;     /* client_body_timeout */
    ngx_msec_t    send_timeout;            /* send_timeout */
    ngx_msec_t    keepalive_timeout;       /* keepalive_timeout */
    ngx_msec_t    lingering_time;          /* lingering_time */
    ngx_msec_t    lingering_timeout;       /* lingering_timeout */
    ngx_msec_t    resolver_timeout;        /* resolver_timeout */

    ngx_resolver_t  *resolver;             /* resolver */

    time_t        keepalive_header;        /* keepalive_timeout */

    ngx_uint_t    keepalive_requests;      /* keepalive_requests */
    ngx_uint_t    keepalive_disable;       /* keepalive_disable */
    ngx_uint_t    satisfy;                 /* satisfy */
    ngx_uint_t    lingering_close;         /* lingering_close */
    ngx_uint_t    if_modified_since;       /* if_modified_since */
    ngx_uint_t    max_ranges;              /* max_ranges */
    ngx_uint_t    client_body_in_file_only; /* client_body_in_file_only */

    ngx_flag_t    client_body_in_single_buffer;
                                           /* client_body_in_singe_buffer */
    ngx_flag_t    internal;                /* internal */ //fzc: 这个internal和r->internal不同, 这里的internal是http_core模块的internal指令用在location中, 表示该location是否只用在内部请求.
    ngx_flag_t    sendfile;                /* sendfile */
#if (NGX_HAVE_FILE_AIO)
    ngx_flag_t    aio;                     /* aio */
#endif
    ngx_flag_t    tcp_nopush;              /* tcp_nopush */
    ngx_flag_t    tcp_nodelay;             /* tcp_nodelay */
    ngx_flag_t    reset_timedout_connection; /* reset_timedout_connection */
    ngx_flag_t    server_name_in_redirect; /* server_name_in_redirect */
    ngx_flag_t    port_in_redirect;        /* port_in_redirect */
    ngx_flag_t    msie_padding;            /* msie_padding */
    ngx_flag_t    msie_refresh;            /* msie_refresh */
    ngx_flag_t    log_not_found;           /* log_not_found */
    ngx_flag_t    log_subrequest;          /* log_subrequest */
    ngx_flag_t    recursive_error_pages;   /* recursive_error_pages */
    ngx_flag_t    server_tokens;           /* server_tokens */
    ngx_flag_t    chunked_transfer_encoding; /* chunked_transfer_encoding */
    ngx_flag_t    etag;                    /* etag */

#if (NGX_HTTP_GZIP)
    ngx_flag_t    gzip_vary;               /* gzip_vary */

    ngx_uint_t    gzip_http_version;       /* gzip_http_version */
    ngx_uint_t    gzip_proxied;            /* gzip_proxied */

#if (NGX_PCRE)
    ngx_array_t  *gzip_disable;            /* gzip_disable */
#endif
#endif

#if (NGX_HAVE_OPENAT)
    ngx_uint_t    disable_symlinks;        /* disable_symlinks */
    ngx_http_complex_value_t  *disable_symlinks_from;
#endif

    ngx_array_t  *error_pages;             /* error_page */ //fzc: 元素为ngx_http_err_page_t,在ngx_http_core_error_page中添加
    ngx_http_try_file_t    *try_files;     /* try_files */

    ngx_path_t   *client_body_temp_path;   /* client_body_temp_path */

    ngx_open_file_cache_t  *open_file_cache;
    time_t        open_file_cache_valid;
    ngx_uint_t    open_file_cache_min_uses;
    ngx_flag_t    open_file_cache_errors;
    ngx_flag_t    open_file_cache_events;

    ngx_log_t    *error_log;

    ngx_uint_t    types_hash_max_size;
    ngx_uint_t    types_hash_bucket_size;

    ngx_queue_t  *locations; //fzc: 元素为ngx_http_location_queue_t, 用来增加子location, server block下的所有location都属于server block的null location

#if 0
    ngx_http_core_loc_conf_t  *prev_location;
#endif
};


typedef struct {
    ngx_queue_t                      queue; //fzc: kernel风格双向list, 本质就是指针, 使该结构体可构成queue
    ngx_http_core_loc_conf_t        *exact; //fzc:? 还不清楚exact和inclusive的区别, 见ngx_http_add_location的逻辑
    ngx_http_core_loc_conf_t        *inclusive;
    ngx_str_t                       *name; //fzc: location的name, 即location指令后面的路由名
    u_char                          *file_name;
    ngx_uint_t                       line;
    ngx_queue_t                      list; //fzc:? 挂嵌套location吗?
} ngx_http_location_queue_t;


struct ngx_http_location_tree_node_s {
    ngx_http_location_tree_node_t   *left;
    ngx_http_location_tree_node_t   *right;
    ngx_http_location_tree_node_t   *tree;

    ngx_http_core_loc_conf_t        *exact;
    ngx_http_core_loc_conf_t        *inclusive;

    u_char                           auto_redirect;
    u_char                           len;
    u_char                           name[1];
};


void ngx_http_core_run_phases(ngx_http_request_t *r);
ngx_int_t ngx_http_core_generic_phase(ngx_http_request_t *r,
    ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_rewrite_phase(ngx_http_request_t *r,
    ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_find_config_phase(ngx_http_request_t *r,
    ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_post_rewrite_phase(ngx_http_request_t *r,
    ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_access_phase(ngx_http_request_t *r,
    ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_post_access_phase(ngx_http_request_t *r,
    ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_try_files_phase(ngx_http_request_t *r,
    ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r,
    ngx_http_phase_handler_t *ph);


void *ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash);
ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r);
void ngx_http_set_exten(ngx_http_request_t *r);
ngx_int_t ngx_http_set_etag(ngx_http_request_t *r);
ngx_int_t ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status,
    ngx_str_t *ct, ngx_http_complex_value_t *cv);
u_char *ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *name,
    size_t *root_length, size_t reserved);
ngx_int_t ngx_http_auth_basic_user(ngx_http_request_t *r);
#if (NGX_HTTP_GZIP)
ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r);
#endif


ngx_int_t ngx_http_subrequest(ngx_http_request_t *r,
    ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **sr,
    ngx_http_post_subrequest_t *psr, ngx_uint_t flags);
ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r,
    ngx_str_t *uri, ngx_str_t *args);
ngx_int_t ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name);


ngx_http_cleanup_t *ngx_http_cleanup_add(ngx_http_request_t *r, size_t size);


typedef ngx_int_t (*ngx_http_output_header_filter_pt)(ngx_http_request_t *r);
typedef ngx_int_t (*ngx_http_output_body_filter_pt)
    (ngx_http_request_t *r, ngx_chain_t *chain);


ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *chain);
ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *chain);


ngx_int_t ngx_http_set_disable_symlinks(ngx_http_request_t *r,
    ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of);

ngx_int_t ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr,
    ngx_array_t *headers, ngx_str_t *value, ngx_array_t *proxies,
    int recursive);


extern ngx_module_t  ngx_http_core_module;

extern ngx_uint_t ngx_http_max_module;

extern ngx_str_t  ngx_http_core_get_method;


#define ngx_http_clear_content_length(r)                                      \
                                                                              \
    r->headers_out.content_length_n = -1;                                     \
    if (r->headers_out.content_length) {                                      \
        r->headers_out.content_length->hash = 0;                              \
        r->headers_out.content_length = NULL;                                 \
    }
                                                                              \
#define ngx_http_clear_accept_ranges(r)                                       \
                                                                              \
    r->allow_ranges = 0;                                                      \
    if (r->headers_out.accept_ranges) {                                       \
        r->headers_out.accept_ranges->hash = 0;                               \
        r->headers_out.accept_ranges = NULL;                                  \
    }

#define ngx_http_clear_last_modified(r)                                       \
                                                                              \
    r->headers_out.last_modified_time = -1;                                   \
    if (r->headers_out.last_modified) {                                       \
        r->headers_out.last_modified->hash = 0;                               \
        r->headers_out.last_modified = NULL;                                  \
    }

#define ngx_http_clear_location(r)                                            \
                                                                              \
    if (r->headers_out.location) {                                            \
        r->headers_out.location->hash = 0;                                    \
        r->headers_out.location = NULL;                                       \
    }

#define ngx_http_clear_etag(r)                                                \
                                                                              \
    if (r->headers_out.etag) {                                                \
        r->headers_out.etag->hash = 0;                                        \
        r->headers_out.etag = NULL;                                           \
    }


#endif /* _NGX_HTTP_CORE_H_INCLUDED_ */
